
package algo.math.evaluator.base;

import java.util.Dictionary;
import java.util.Hashtable;
import algo.math.evaluator.base.exceptions.InvalidToken;
import algo.math.evaluator.base.exceptions.UnrecognizedToken;
import algo.math.evaluator.context.EvaluationContext;
import algo.math.evaluator.context.operator.interfaces.IOperator;


/**
 * Represent a number base.
 * Base 10 by default.
 */
public class Base implements IBase {

	/**Base 10 digits*/
	private final String _base10 = "0123456789";
	
	/** The base digits */
	private String _base = _base10 ;
	
	/**Store the weight/digits lookup table*/
	private Dictionary<Character, Integer> _dic;
	
	
	/**
	 * Instantiates a new base.
	 */
	public Base()
	{
		setBase10();
	}
	
	
	/**
	 * Sets the base to base10.
	 */
	private void setBase10()
	{
		_dic = new Hashtable<Character, Integer>();

		for (int i =0;i<_base10.length();i++)
		{
			_dic.put(_base10.charAt(i), i);
		}
	}
	
	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#setBase(java.lang.String)
	 */
	@Override
	public void setBase(String base)throws InvalidToken {
		
		if (!base.equals(""))
		{
			_dic = new Hashtable<Character, Integer>();
			
			for (int i =0;i<base.length();i++)
			{
				if (null != EvaluationContext.GetInstance().getComponentById(IOperator.class, String.valueOf(base.charAt(i)))) //Helper.getInstance().getOperator(String.valueOf(base.charAt(i))))
				{
					setBase10();
					throw new InvalidToken("Token "+ base.charAt(i) + " is a registered operator");
				}
				_dic.put(base.charAt(i), i);
			}
			
			_base = base;
		}
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
			return _base;
	}
	
	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#weightOf(char)
	 */
	@Override
	public int weightOf(char variable)  throws UnrecognizedToken {
		try
		{
		return _dic.get(variable)+1;
		}
		catch (Exception e)
		{
			throw new UnrecognizedToken("Token does not belong to this base.");
		}
	}

	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#valueOf(java.lang.String)
	 */
	@Override
    public int valueOf(String value) throws UnrecognizedToken {  

        Boolean isNegative = false; 
        
        if (value.contains("-"))
        {
        	isNegative = true;
        	value = value.replaceFirst("-", "");
        }
        
        int i = value.length();  
        int r = 0;  
        int m = 1;  
        int base = _base.length();
        
        while( i > 0 ) {
        	r += ( (_base.indexOf( value.substring( i - 1, i ) )) * m ); 
            m *= base;  
            i--;  
        }  
        
        if (isNegative)
	        {
        	if (r<0)
        	{
        		return (r*(-1));
        	}
	        	return (Integer.valueOf("-"+r));
	        }

        	return r;  
        
        
    }  
	
	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#valueOf(int)
	 */
	@Override
    public String valueOf(int value)  {

        Boolean isNegative = false;
        
        if (value<0)
        {
        	isNegative = true;
        	value = Integer.valueOf( String.valueOf(value).replaceFirst("-", ""));
        }
		
    	if (value==0) return  String.valueOf(_base.charAt(0));
    	int base = _base.length();
        String s = "";
        while (value > 0) {
           int d = value % base;
           s = _base.charAt(d) + s;
           value /= base;
        }
        
        if (isNegative)
        {
    	
        	return ("-"+s);
        }

    	return s;  
     }
	
	
	
	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#valueOf(double)
	 */
	@Override
    public String valueOf(double value)  {
	       Boolean isNegative = false;
	        
	        if (value<0)
	        {
	        	isNegative = true;
	        	value = Math.abs(value);
	        }
		
		int val = (int)value;
    	if (value==0) return  String.valueOf(_base.charAt(0));
    	int base = _base.length();
        String s = "";
        while (val > 0) {
           int d = val % base;
           s = _base.charAt(d) + s;
           val /= base;
        }
        
        if (isNegative)
        	return "-"+s;
        
        return s;
     }

	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#isBaseToken(char)
	 */
	@Override
	public Boolean isBaseToken(char variable) {
		try
		{
		@SuppressWarnings("unused")
		int y = _dic.get(variable);
		return true;
		}
		catch (Exception e)
		{
			return false;	
		}
	}

	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#isSeparator(char)
	 */
	@Override
	public Boolean isSeparator(char value) {
			for (int i = 0; i < Base.SEPARATOR.length;i++)
			{
				if (Base.SEPARATOR[i]==value)
					return true;
				
			}
			return false;
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#isSeparator(java.lang.String)
	 */
	@Override
	public Boolean isSeparator(String value) {
		for (int i = 0; i < Base.SEPARATOR_STRING.length;i++)
		{
			if (Base.SEPARATOR_STRING[i]==value)
				return true;
			
		}
		return false;
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#isBlank(char)
	 */
	@Override
	public Boolean isBlank(char value) {
		for (int i = 0; i < Base.BLANK_CHAR.length;i++)
		{
			if (Base.BLANK_CHAR[i]==value)
				return true;
			
		}
		return false;
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#isBlank(java.lang.String)
	 */
	@Override
	public Boolean isBlank(String value) {
		for (int i = 0; i < Base.BLANK_STRING.length;i++)
		{
			if (Base.BLANK_STRING[i]==value)
				return true;
			
		}
		return false;
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#maxValue()
	 */
	@Override
	public String maxValue() {
		return String.valueOf(_base.charAt(_base.length()-1));
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#weightOf(java.lang.String)
	 */
	@Override
	public int weightOf(String variable) throws UnrecognizedToken {
		try
		{
		return _dic.get(variable.charAt(0))+1;
		}
		catch (Exception e)
		{
			throw new UnrecognizedToken("Token does not belong to this base.");
		}
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#toStringArray()
	 */
	@Override
	public String[] toStringArray() {
		
		String [] stringArray= new String [_base.toCharArray().length];
		char [] charArray = _base.toCharArray();
		for (int i =0; i<charArray.length;i++){
			stringArray[i] = String.valueOf(charArray[i]);
		}
		return  stringArray;
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#maxWeight()
	 */
	@Override
	public long maxWeight() {
		//return _base.length()-1;
		return _base.length();
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#getBase10()
	 */
	@Override
	public IBase getBase10() {
		IBase b10 = new Base();
		try {
			b10.setBase(_base10);
		} catch (InvalidToken e) {
			e.printStackTrace();
		}
		return b10;
	}


	/* (non-Javadoc)
	 * @see algo.math.evaluator.base.IBase#minValue()
	 */
	@Override
	public String minValue() {
		return String.valueOf(_base.charAt(0));
	}
}
